<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="keywords" content="Hexo Theme Keep">
    <meta name="description" content="Hexo Theme Keep">
    <meta name="author" content="aaton">
    
    <title>
        
            Vue3之ref与reactive |
        
        aaton&#39;s study notes
    </title>
    
<link rel="stylesheet" href="/css/style.css">

    <link rel="shortcut icon" href="/images/logo.svg">
    
<link rel="stylesheet" href="/font/css/fontawesome.min.css">

    
<link rel="stylesheet" href="/font/css/regular.min.css">

    
<link rel="stylesheet" href="/font/css/solid.min.css">

    
<link rel="stylesheet" href="/font/css/brands.min.css">

    <script id="hexo-configurations">
    let KEEP = window.KEEP || {}
    KEEP.hexo_config = {"hostname":"example.com","root":"/","language":"en"}
    KEEP.theme_config = {"toc":{"enable":false,"number":false,"expand_all":false,"init_open":false},"style":{"primary_color":"#0066cc","logo":"/images/logo.svg","favicon":"/images/logo.svg","avatar":"/images/avatar.svg","font_size":null,"font_family":null,"hover":{"shadow":false,"scale":false},"first_screen":{"enable":true,"header_transparent":true,"background_img":"/images/bg.svg","description":"Keep writing and Keep loving.","font_color":null,"hitokoto":true},"scroll":{"progress_bar":false,"percent":false}},"local_search":{"enable":false,"preload":false},"code_copy":{},"code_block":{"tools":{"enable":true,"style":"default"},"highlight_theme":"default"},"side_tools":{},"pjax":{"enable":false},"lazyload":{"enable":false},"comment":{"enable":false,"use":"valine","valine":{"appid":null,"appkey":null,"server_urls":null,"placeholder":null},"gitalk":{"github_id":null,"github_admins":null,"repository":null,"client_id":null,"client_secret":null,"proxy":null},"twikoo":{"env_id":null,"region":null,"version":"1.6.8"},"waline":{"server_url":null,"reaction":false,"version":2}},"post":{"author_label":{"enable":true,"auto":true,"custom_label_list":["Trainee","Engineer","Architect"]},"word_count":{"enable":true,"wordcount":true,"min2read":true},"img_align":"left","copyright_info":false},"version":"3.6.1"}
    KEEP.language_ago = {"second":"%s seconds ago","minute":"%s minutes ago","hour":"%s hours ago","day":"%s days ago","week":"%s weeks ago","month":"%s months ago","year":"%s years ago"}
    KEEP.language_code_block = {"copy":"Copy code","copied":"Copied","fold":"Fold code block","folded":"Folded"}
    KEEP.language_copy_copyright = {"copy":"Copy copyright info","copied":"Copied","title":"Original article title","author":"Original article author","link":"Original article link"}
  </script>
<meta name="generator" content="Hexo 6.3.0"></head>


<body>
<div class="progress-bar-container">
    

    
</div>


<main class="page-container">

    

    <div class="page-main-content">

        <div class="page-main-content-top">
            
<header class="header-wrapper">

    <div class="header-content">
        <div class="left">
            
                <a class="logo-image" href="/">
                    <img src="/images/logo.svg">
                </a>
            
            <a class="logo-title" href="/">
               aaton&#39;s study notes
            </a>
        </div>

        <div class="right">
            <div class="pc">
                <ul class="menu-list">
                    
                        <li class="menu-item">
                            <a class=""
                               href="/"
                            >
                                HOME
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/archives"
                            >
                                ARCHIVES
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/tags"
                            >
                                TAGS
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/categories"
                            >
                                CATEGORIES
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/about"
                            >
                                ABOUT
                            </a>
                        </li>
                    
                    
                </ul>
            </div>
            <div class="mobile">
                
                <div class="icon-item menu-bar">
                    <div class="menu-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <div class="header-drawer">
        <ul class="drawer-menu-list">
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/">HOME</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/archives">ARCHIVES</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/tags">TAGS</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/categories">CATEGORIES</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/about">ABOUT</a>
                </li>
            
        </ul>
    </div>

    <div class="window-mask"></div>

</header>


        </div>

        <div class="page-main-content-middle">

            <div class="main-content">

                
                    <div class="fade-in-down-animation">
    <div class="post-page-container">
        <div class="article-content-container">

            <div class="article-title">
                <span class="title-hover-animation">Vue3之ref与reactive</span>
            </div>

            
                <div class="article-header">
                    <div class="avatar">
                        <img src="/images/avatar.svg">
                    </div>
                    <div class="info">
                        <div class="author">
                            <span class="name">aaton</span>
                            
                                <span class="author-label">Lv3</span>
                            
                        </div>
                        <div class="meta-info">
                            
<div class="article-meta-info">
    <span class="article-date article-meta-item">
        
            <i class="fa-regular fa-calendar-plus"></i>&nbsp;
        
        <span class="pc">2023-06-05 11:00:11</span>
        <span class="mobile">2023-06-05 11:00</span>
    </span>
    
        <span class="article-update-date article-meta-item">
        <i class="fas fa-file-pen"></i>&nbsp;
        <span class="pc">2023-05-16 17:58:34</span>
    </span>
    
    
        <span class="article-categories article-meta-item">
            <i class="fas fa-folder"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/categories/Vue3/">Vue3</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fas fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/ref/">ref</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/reactive/">reactive</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/shallowRef/">shallowRef</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/shallowReactive/">shallowReactive</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/toRef/">toRef</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/toRefs/">toRefs</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/toRow/">toRow</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
        <span class="article-wordcount article-meta-item">
            <i class="fas fa-file-word"></i>&nbsp;<span>2.6k Words</span>
        </span>
    
    
        <span class="article-min2read article-meta-item">
            <i class="fas fa-clock"></i>&nbsp;<span>10 Mins</span>
        </span>
    
    
        <span class="article-pv article-meta-item">
            <i class="fas fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

                        </div>
                    </div>
                </div>
            

            <div class="article-content keep-markdown-body">
                

                <p><img src="https://cn.bing.com/th?id=OHR.KiteDay_ZH-CN7813901578_1920x1200.jpg&rf=LaDigue_1920x1200.jpg" alt="bing.com-阿德莱德国际风筝节，澳大利亚" title="bing.com-阿德莱德国际风筝节，澳大利亚"></p>
<p>Vue3中实现响应式数据的方法：ref与reactive详解。</p>
<span id="more"></span>

<p>Vue3中响应式是通过ES6的Proxy实现的，实现数据相应的方法是ref和reactive。所谓响应式就是界面和数据同步，能实现实时更新。<strong>ref本质也是reactive，ref(obj)等价于reactive({value: obj})</strong></p>
<p><em>Vue2中响应式是通过defineProperty实现的</em>。</p>
<h1 id="1-reactive"><a href="#1-reactive" class="headerlink" title="1.reactive"></a>1.reactive</h1><p>返回一个对象的响应式代理。</p>
<p>响应式转换是“深层”的：它会影响到<strong>所有嵌套的属性</strong>。一个响应式对象也将深层地<strong>解包任何 ref 属性，同时保持响应性</strong>。</p>
<p>值得注意的是，当访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时，不会执行 ref 的解包。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">const books = reactive([ref(&#x27;Vue 3 Guide&#x27;)])</span><br><span class="line">// 这里需要 .value</span><br><span class="line">console.log(books[0].value)</span><br><span class="line"></span><br><span class="line">const map = reactive(new Map([[&#x27;count&#x27;, ref(0)]]))</span><br><span class="line">// 这里需要 .value</span><br><span class="line">console.log(map.get(&#x27;count&#x27;).value)</span><br></pre></td></tr></table></figure>

<p>若要避免深层响应式转换，只想保留对这个对象顶层次访问的响应性，请使用<code>shallowReactive()</code>作替代。</p>
<p>返回的对象以及其中嵌套的对象都会通过 ES Proxy 包裹，因此不等于源对象，建议只使用响应式代理，避免使用原始对象。</p>
<ul>
<li>reactive的参数必须是一个对象，它能够将复杂数据类型变为响应式数据。包括json数据和数组都可以，否则不具有响应式。</li>
<li>如果给reactive传递了其他对象（如时间对象），默认情况下修改对象界面不会自动更新，如果想更新，可以通过给对象重新赋值来解决。</li>
<li>reactive的响应式是深层次的，底层本质是将传入的数据转换为Proxy对象。</li>
</ul>
<blockquote>
<p>Proxy vs defineProperty<br>reactive方法内部是利用ES6的Proxy API来实现的，这里与Vue2中的defineProperty方法有本质的区别。</p>
<ul>
<li>defineProperty只能单一地监听已有属性的修改或者变化，<strong>无法检测到对象属性的新增或删除</strong>，而Proxy可以轻松实现。</li>
<li>defineProperty<strong>无法监听属性值是数组类型的变化</strong>，而Proxy可以轻松实现。</li>
</ul>
</blockquote>
<p>reactive的实现：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">// 首先，判断是否为对象</span><br><span class="line">const isObject =( val )=&gt; &#123;</span><br><span class="line">    return val !== null &amp;&amp; typeof val === &#x27;object&#x27;;</span><br><span class="line">&#125;</span><br><span class="line">// 判断key是否存在</span><br><span class="line">const hasOwn = (value, key) =&gt; &#123; </span><br><span class="line">    return Object.prototype.hasOwnProperty.call(value, key);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">export function reactive(value) &#123;</span><br><span class="line">    // 首先先判断是否为对象</span><br><span class="line">    if (!isObject(value)) return target;</span><br><span class="line"></span><br><span class="line">    const handler = &#123;</span><br><span class="line">        get(value, key, receiver) &#123;</span><br><span class="line">            console.log(`获取对象属性$&#123;key&#125;值`)</span><br><span class="line">            // 收集依赖 ...</span><br><span class="line">            const result = Reflect.get(value, key, receiver)</span><br><span class="line">            // 深度监听（惰性）</span><br><span class="line">            if (isObject(result)) &#123;</span><br><span class="line">                return reactive(result);</span><br><span class="line">            &#125;</span><br><span class="line">            return result;</span><br><span class="line">        &#125;,</span><br><span class="line"></span><br><span class="line">        set(value, key, value, receiver) &#123;</span><br><span class="line">            console.log(`设置对象属性$&#123;key&#125;值`)</span><br><span class="line"></span><br><span class="line">            // 首先先获取旧值</span><br><span class="line">            const oldValue = Reflect.get(value, key, reactive)</span><br><span class="line"></span><br><span class="line">            let res = Reflect.set(value, key, value, receiver);</span><br><span class="line"></span><br><span class="line">            if (res &amp;&amp; oldValue !== value) &#123;</span><br><span class="line">                // 更新操作 ...</span><br><span class="line">            &#125;</span><br><span class="line">            return res</span><br><span class="line">        &#125;,</span><br><span class="line"></span><br><span class="line">        deleteProperty(value, key) &#123;</span><br><span class="line">            console.log(`删除对象属性$&#123;key&#125;值`)</span><br><span class="line"></span><br><span class="line">            // 先判断是否有key</span><br><span class="line">            const hadKey = hasOwn(value, key)</span><br><span class="line">            const res = Reflect.deleteProperty(value, key)</span><br><span class="line"></span><br><span class="line">            if (hadKey &amp;&amp; res) &#123;</span><br><span class="line">                // 更新操作 ...</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            return res</span><br><span class="line">        &#125;,</span><br><span class="line"></span><br><span class="line">        // 其他方法</span><br><span class="line">        // ...</span><br><span class="line">    &#125;</span><br><span class="line">    return new Proxy(value, handler)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">const obj = &#123; a: &#123; b: &#123; c: 1 &#125; &#125; &#125;;</span><br><span class="line">const proxy = reactive(obj);</span><br><span class="line"></span><br><span class="line">proxy.a.b.c = 100;</span><br><span class="line"></span><br><span class="line">// 获取对象属性a值</span><br><span class="line">// 获取a值对象属性b值</span><br><span class="line">// 设置b值对象属性c值 100</span><br></pre></td></tr></table></figure>

<p>从源码中可以看出：</p>
<ul>
<li>reactive 的参数必须是对象或者数组。</li>
<li>页面的响应式就是创建原始数据对象的响应式副本，即将<strong>引用数据类型的数据转换为响应式数据</strong>。</li>
</ul>
<p>那么对于基本数据类型如何实现响应式呢？vue源码给出的的解决方案是把基本数据类型套一个对象外壳变成一个对象：这个对象只有一个value属性，value属性的值就等于这个基本数据类型的值。然后，就可以用reactive方法将这个对象，变成响应式的Proxy对象。实际上就是：**ref(0) 等同于 reactive( { value:0 })**。</p>
<hr>
<h1 id="2-ref"><a href="#2-ref" class="headerlink" title="2.ref"></a>2.ref</h1><p>接受一个内部值，返回一个响应式的、可更改的 ref 对象，此对象只有一个指向其内部值的属性 .value。</p>
<p>当我们只想让某个变量实现响应式的时候，采用reactive就会比较麻烦，因此vue3提供了ref方法进行简单值的监听，但并不是说ref只能传入简单值，他的底层是reactive，所以reactive有的，他都有。</p>
<p>特点：</p>
<ul>
<li>ref的参数一般是基本数据类型，也可以是对象类型。</li>
<li>如果参数是对象类型，其实底层的本质还是reactive，系统会自动将ref转换为reactive，例如：</li>
</ul>
<blockquote>
<p>ref(1) &#x3D;&#x3D;&#x3D;&gt; reactive({value:1})</p>
</blockquote>
<ul>
<li>在模板中访问ref中的数据，系统会自动帮我们添加.value,在JS中访问ref中的数据，需要手动添加.value。</li>
<li>ref的底层原理同reactive一样，都是Proxy。</li>
</ul>
<p>源码解析：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line">export function ref(value?: unknown) &#123;</span><br><span class="line">  return createRef(value, false)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">function createRef(rawValue: unknown, shallow: boolean) &#123;</span><br><span class="line">  if (isRef(rawValue)) &#123;</span><br><span class="line">    return rawValue</span><br><span class="line">  &#125;</span><br><span class="line">  return new RefImpl(rawValue, shallow)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">const toReactive = &lt;T extends unknown&gt;(value: T): T =&gt;</span><br><span class="line">  isObject(value) ? reactive(value) : value</span><br><span class="line"></span><br><span class="line">class RefImpl&lt;T&gt; &#123;</span><br><span class="line">  private _value: T</span><br><span class="line">  private _rawValue: T</span><br><span class="line"></span><br><span class="line">  public dep?: Dep = undefined</span><br><span class="line">  public readonly __v_isRef = true</span><br><span class="line"></span><br><span class="line">  constructor(value: T, public readonly __v_isShallow: boolean) &#123;</span><br><span class="line">    this._rawValue = __v_isShallow ? value : toRaw(value)</span><br><span class="line">    this._value = __v_isShallow ? value : toReactive(value)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  get value() &#123;</span><br><span class="line">    trackRefValue(this)</span><br><span class="line">    return this._value</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  set value(newVal) &#123;</span><br><span class="line">    const useDirectValue =</span><br><span class="line">      this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)</span><br><span class="line">    newVal = useDirectValue ? newVal : toRaw(newVal)</span><br><span class="line">    if (hasChanged(newVal, this._rawValue)) &#123;</span><br><span class="line">      this._rawValue = newVal</span><br><span class="line">      this._value = useDirectValue ? newVal : toReactive(newVal)</span><br><span class="line">      triggerRefValue(this, newVal)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在vue3中调用ref函数时会js会先new 一个class，这个class监听了value属性的 get 和 set方法 ，实现了在get中收集依赖，在set中触发依赖的双向绑定过程，而如果需要对传入参数深层监听的话，就需要调用我们上面提到的reactive方法。</p>
<p>将一个 ref 赋值给一个 reactive 属性时，该 ref 会被自动解包：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">const count = ref(1)</span><br><span class="line">const obj = reactive(&#123;&#125;)</span><br><span class="line"></span><br><span class="line">obj.count = count</span><br><span class="line"></span><br><span class="line">console.log(obj.count) // 1</span><br><span class="line">console.log(obj.count === count.value) // true</span><br></pre></td></tr></table></figure>

<p>ref()将传入参数的值包装为一个带.value属性的对象：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">const count = ref(0)</span><br><span class="line"></span><br><span class="line">console.log(count) // &#123; value: 0 &#125;</span><br><span class="line">console.log(count.value) // 0</span><br><span class="line"></span><br><span class="line">count.value++</span><br><span class="line">console.log(count.value) // 1</span><br></pre></td></tr></table></figure>

<p>和响应式对象的属性类似，ref 的 .value 属性也是响应式的。同时，<strong>当值为对象类型时，会用 reactive() 自动转换它的 .value</strong>。</p>
<p>一个包含对象类型值的 ref 可以响应式地替换整个对象：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">const objectRef = ref(&#123; count: 0 &#125;)</span><br><span class="line"></span><br><span class="line">// 这是响应式的替换</span><br><span class="line">objectRef.value = &#123; count: 1 &#125;</span><br></pre></td></tr></table></figure>

<p><strong>数组和集合类型的 ref 解包​：</strong></p>
<p>跟响应式对象不同，当 ref 作为响应式数组或像 Map 这种原生集合类型的元素被访问时，不会进行解包。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">const books = reactive([ref(&#x27;Vue 3 Guide&#x27;)])</span><br><span class="line">// 这里需要 .value</span><br><span class="line">console.log(books[0].value)</span><br><span class="line"></span><br><span class="line">const map = reactive(new Map([[&#x27;count&#x27;, ref(0)]]))</span><br><span class="line">// 这里需要 .value</span><br><span class="line">console.log(map.get(&#x27;count&#x27;).value)</span><br></pre></td></tr></table></figure>

<hr>
<h1 id="3-总结"><a href="#3-总结" class="headerlink" title="3. 总结"></a>3. 总结</h1><ul>
<li>reactive 将引用数据类型值变为响应式，使用Proxy实现。</li>
<li>ref 可将基本数据类型和引用数据类型都变成响应式，通过<strong>套壳成对象</strong>，监听对象class的value属性的get和set方法实现，但是当传入的值为引用数据类型时实际上内部还是使用reactive 方法进行的处理。</li>
<li>推荐基本数据类型使用ref，引用数据类型使用 reactive。</li>
<li>在JS中访问ref的值需要手动添加.value，访问reactive不需要。</li>
<li>响应式的底层原理都是Proxy。</li>
</ul>
<hr>
<h1 id="4-shallowRef和shallowReactive"><a href="#4-shallowRef和shallowReactive" class="headerlink" title="4.shallowRef和shallowReactive"></a>4.shallowRef和shallowReactive</h1><blockquote>
<p>递归监听和非递归监听： </br><br>ref和reactive都属于递归监听，也就是数据的每一层都是响应式的，如果数据量比较大，非常消耗性能，非递归监听只会监听数据的第一层。</p>
</blockquote>
<h3 id="（1）-ref和shawllowRef"><a href="#（1）-ref和shawllowRef" class="headerlink" title="（1）.ref和shawllowRef"></a>（1）.ref和shawllowRef</h3><ul>
<li>ref定义的数据每一层都是响应式数据</li>
<li>shallow定义的数据，只有第一层是响应式的，即只有在更改.value的时候才能实现响应式。</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">let age = ref(&#123;</span><br><span class="line">      a: &#x27;1&#x27;,</span><br><span class="line">      f: &#123;</span><br><span class="line">        b: &#x27;2&#x27;,</span><br><span class="line">        s:&#123;</span><br><span class="line">          c: &#x27;3&#x27;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">//打印各层数据</span><br><span class="line">console.log(age);</span><br><span class="line">console.log(age.value);</span><br><span class="line">console.log(age.value.f);</span><br><span class="line">console.log(age.value.f.s);</span><br></pre></td></tr></table></figure>

<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f7a40e31cc87478c846c0bdfdfdd15ae~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp" alt="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农" title="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农"></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">let age = shallowRef(&#123;</span><br><span class="line">      a: &#x27;1&#x27;,</span><br><span class="line">      f: &#123;</span><br><span class="line">        b: &#x27;2&#x27;,</span><br><span class="line">        s:&#123;</span><br><span class="line">          c: &#x27;3&#x27;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">//打印各层数据</span><br><span class="line">console.log(age);</span><br><span class="line">console.log(age.value);</span><br><span class="line">console.log(age.value.f);</span><br><span class="line">console.log(age.value.f.s);</span><br></pre></td></tr></table></figure>

<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f1f3efe46e0648b6af1b3930785847ff~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp" alt="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农" title="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农"></p>
<blockquote>
<p>使用shallowRef后，可以通过triggerRef()方法主动更新界面，实现界面刷新。</p>
</blockquote>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">function doSome()&#123;</span><br><span class="line">  age.value.f.s.c = &#x27;c&#x27;;</span><br><span class="line">  //主动更新界面</span><br><span class="line">  triggerRef(age);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="（2）-reactive和shallowReactive"><a href="#（2）-reactive和shallowReactive" class="headerlink" title="（2）.reactive和shallowReactive"></a>（2）.reactive和shallowReactive</h3><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1227b94485f6466a972715f38cf70046~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp" alt="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农" title="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农"></p>
<blockquote>
<p>注意：shallowReactive没有类似triggerRef()的方法。</p>
</blockquote>
<hr>
<h1 id="5-toRow"><a href="#5-toRow" class="headerlink" title="5.toRow"></a>5.toRow</h1><p>有些时候我们不希望数据进行响应式实时更新，可以通过toRaw获取ref或reactive引用的原始数据，通过修改原始数据，不会造成界面的更新，只有通过修改ref和reactive包装后的数据时才会发生界面响应式变化。</p>
<h1 id="6-markRow"><a href="#6-markRow" class="headerlink" title="6.markRow"></a>6.markRow</h1><p>与toRaw不同，markRaw包装后的数据永远不会被追踪。</p>
<h1 id="7-toRef和toRefs"><a href="#7-toRef和toRefs" class="headerlink" title="7.toRef和toRefs"></a>7.toRef和toRefs</h1><p>ref和toRef都是用来构造响应式数据。</p>
<h3 id="（1）-ref"><a href="#（1）-ref" class="headerlink" title="（1）.ref"></a>（1）.ref</h3><p>复制，修改响应式数据不会影响以前的数据，数据发生改变界面就会自动更新。<br>ref转换后是一个<strong>RefImpl</strong>类型。<br><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/410dcb0309fe493aba83e287049657c1~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp" alt="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农" title="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农"></p>
<p>可以看到，使用ref对一个对象的某个简单数据类型属性进行响应式改造后，通过修改响应式数据<strong>不会影响到原始数据</strong>。如上图中，通过state1修改值后，obj1中的a属性值没有发生变化。这里有个注意点：修改的这个属性<strong>必须是简单数据类型</strong>，一个具体的值，不能是引用，如果该属性也是一个对象，则会影响，因为对象是引用类型。</p>
<p>假如上面例子中传入state1的是obj1.f，则情况完全不同。</p>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/53ebf8e0d3824df0ba761b42b6fdd0ce~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp" alt="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农" title="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农"></p>
<h3 id="（2）-toRef"><a href="#（2）-toRef" class="headerlink" title="（2）.toRef"></a>（2）.toRef</h3><p>如果使用toRef来转换，则修改响应式数据会影响到原始数据，数据发生改变，但是界面不会自动更新</p>
<p>转换后的是一个<strong>ObjectRefImpl</strong>类型。<br><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/011e7d8c8eda46e8a5b8ad1733a52f12~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp" alt="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农" title="稀土掘金 ： Vue3第一篇之ref和reactive详解扩展 - 四季如春的业余小码农"></p>
<hr>
<p><em><strong>本文参考文献：</strong></em></p>
<p><em><strong><a class="link"   target="_blank" rel="noopener" href="https://www.zhihu.com/question/467331620" >知乎 ： “Vue3 中有没有 reactive 能做而 ref 做不了的场景？”问题中 源码时代-源哥的回答 - vue3的reactive和ref区别<i class="fas fa-external-link-alt"></i></a></strong></em></p>
<p><em><strong><a class="link"   target="_blank" rel="noopener" href="https://cn.vuejs.org/guide/essentials/reactivity-fundamentals.html#reactive-variables-with-ref" >Vue官网 ： 响应式基础<i class="fas fa-external-link-alt"></i></a></strong></em></p>
<p><em><strong><a class="link"   target="_blank" rel="noopener" href="https://cn.vuejs.org/api/reactivity-core.html#reactive" >Vue官网 ： 响应式API<i class="fas fa-external-link-alt"></i></a></strong></em></p>
<p><em><strong><a class="link"   target="_blank" rel="noopener" href="https://juejin.cn/post/7073722163924041741#heading-6" >稀土掘金 : 详解Vue3中ref与reactive的用法与区别<i class="fas fa-external-link-alt"></i></a></strong></em></p>
<p><em><strong><a class="link"   target="_blank" rel="noopener" href="https://juejin.cn/post/6977929393511514148" >稀土掘金 : Vue3第一篇之ref和reactive详解扩展<i class="fas fa-external-link-alt"></i></a></strong></em></p>

            </div>

            

            
                <ul class="post-tags-box">
                    
                        <li class="tag-item">
                            <a href="/tags/ref/">#ref</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/reactive/">#reactive</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/shallowRef/">#shallowRef</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/shallowReactive/">#shallowReactive</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/toRef/">#toRef</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/toRefs/">#toRefs</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/toRow/">#toRow</a>&nbsp;
                        </li>
                    
                </ul>
            

            
                <div class="article-nav">
                    
                        <div class="article-prev">
                            <a class="prev"
                               rel="prev"
                               href="/2023/06/05/Vue3%E4%B9%8Bwatch%E5%92%8Ccomputed/"
                            >
                            <span class="left arrow-icon flex-center">
                              <i class="fas fa-chevron-left"></i>
                            </span>
                                <span class="title flex-center">
                                <span class="post-nav-title-item">Vue3之watch和computed</span>
                                <span class="post-nav-item">Prev posts</span>
                            </span>
                            </a>
                        </div>
                    
                    
                        <div class="article-next">
                            <a class="next"
                               rel="next"
                               href="/2023/06/05/Typescript%E4%B9%8B%E6%B3%9B%E5%9E%8B/"
                            >
                            <span class="title flex-center">
                                <span class="post-nav-title-item">Typescript之泛型</span>
                                <span class="post-nav-item">Next posts</span>
                            </span>
                                <span class="right arrow-icon flex-center">
                              <i class="fas fa-chevron-right"></i>
                            </span>
                            </a>
                        </div>
                    
                </div>
            

            
        </div>

        
    </div>
</div>


                
            </div>

        </div>

        <div class="page-main-content-bottom">
            
<footer class="footer">
    <div class="info-container">
        <div class="copyright-info info-item">
            &copy;
            
                <span>2020</span> -
            
            2024
            
                &nbsp;<i class="fas fa-heart icon-animate"></i>
                &nbsp;<a href="/">aaton</a>
            
        </div>
        
            <script async 
                    src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="website-count info-item">
                
                    Visitor Count&nbsp;<span id="busuanzi_value_site_uv"></span>&ensp;
                
                
                    Totalview&nbsp;<span id="busuanzi_value_site_pv"></span>
                
            </div>
        
        <div class="theme-info info-item">
            Powered by <a target="_blank" href="https://hexo.io">Hexo</a>&nbsp;|&nbsp;Theme&nbsp;<a class="theme-version" target="_blank" href="https://github.com/XPoet/hexo-theme-keep">Keep v3.6.1</a>
        </div>
        
        
    </div>
</footer>

        </div>
    </div>

    
        <div class="post-tools">
            <div class="post-tools-container">
    <ul class="tools-list">
        <!-- TOC aside toggle -->
        

        <!-- go comment -->
        
    </ul>
</div>

        </div>
    

    <div class="right-bottom-side-tools">
        <div class="side-tools-container">
    <ul class="side-tools-list">
        <li class="tools-item tool-font-adjust-plus flex-center">
            <i class="fas fa-search-plus"></i>
        </li>

        <li class="tools-item tool-font-adjust-minus flex-center">
            <i class="fas fa-search-minus"></i>
        </li>

        <li class="tools-item tool-dark-light-toggle flex-center">
            <i class="fas fa-moon"></i>
        </li>

        <!-- rss -->
        

        
            <li class="tools-item tool-scroll-to-top flex-center">
                <i class="fas fa-arrow-up"></i>
            </li>
        

        <li class="tools-item tool-scroll-to-bottom flex-center">
            <i class="fas fa-arrow-down"></i>
        </li>
    </ul>

    <ul class="exposed-tools-list">
        <li class="tools-item tool-toggle-show flex-center">
            <i class="fas fa-cog fa-spin"></i>
        </li>
        
    </ul>
</div>

    </div>

    <div class="zoom-in-image-mask">
    <img class="zoom-in-image">
</div>


    

</main>




<script src="/js/utils.js"></script>

<script src="/js/main.js"></script>

<script src="/js/header-shrink.js"></script>

<script src="/js/back2top.js"></script>

<script src="/js/dark-light-toggle.js"></script>







    
<script src="/js/code-block.js"></script>





<div class="post-scripts">
    
        
<script src="/js/post-helper.js"></script>

        
        
    
</div>



</body>
</html>
